﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using devtm.Aop.Emit;
using devtm.Aop.InternalProcess;
using System.Reflection;
using devtm.Aop.Convert;
using devtm.Aop.Event;
using devtm.Aop.Linq.Boxs;
using devtm.Aop.Extensions;
using devtm.Aop;

namespace devtm.Aop.Linq
{
    

   

    public class GroupMethod<T> : GroupMethod
    {

        


        internal GroupMethod(Proxy<T> parent, string label)
        {
            this.parent = parent;
            base.label = label;
        }
       


        #region Selectors


        public GroupMethod<T> Select(string methodName, params Type[] parameters)
        {

            methodName.NotNull("methodName");

            List<MethodSign> lst = new List<MethodSign>();

            foreach (MethodInfo item in parent.Type.GetMembers().Where(e => e.Name == methodName && e is MethodInfo))            
                if (parameters == null | Match(parameters, item.GetParameters()))
                    lst.Add(item.ExtractMethodSignature());
                                      
            RegisterSignatures(lst);

            return this;

        }

        private bool Match(Type[] p1, ParameterInfo[] p2)
        {

            if (p1.Length != p2.Length)
                return false;

            for (int i = 0; i < p1.Length; i++)
            {

                Type t1 = p1[i];                
                Type t2 = p2[i].ParameterType;

                if (t1 != t2)
                    return false;

            }

            return true;

        }


        public GroupMethod<T> Select(Expression<Action<T>> expression)
        {
            
            expression.NotNull("expression");

            var exp = expression.GetMemberOfExpression();

            foreach (var item in exp)
            {
                var signature = new MethodSign(item);
                if (!typeof(T).IsInterface)
                    RequireHelper.Overridable(item);
                RegisterSignatures(new[] { signature });
            }

            return this;

        }

        public GroupMethod<T> Select(Expression<Func<T, object>> expression)
        {

            expression.NotNull("expression");

            var exp = expression.GetMemberOfExpression();

            foreach (var item in exp)
            {
                var signature = new MethodSign(item);
                if (!typeof(T).IsInterface)
                    RequireHelper.Overridable(item);
                RegisterSignatures(new[] { signature });
            }

            return this;

        }

        public GroupMethod<T> SelectAllGetters()
        {
            var methods = typeof(T)
                .GetMethodsToIntercept()
                .SelectPropertyGetters();
            RegisterSignatures(methods.Select(m => m.ExtractMethodSignature()));
            return this;
        }

        public GroupMethod<T> SelectAllSetters()
        {
            var methods = typeof(T)
                .GetMethodsToIntercept()
                .SelectPropertySetters();
            RegisterSignatures(methods.Select(m => m.ExtractMethodSignature()));
            return this;
        }

        public GroupMethod<T> SelectAll()
        {
            var methods = typeof(T).GetMethodsToIntercept();
            RegisterSignatures(methods.Select(m => m.ExtractMethodSignature()));
            return this;
        }

        public GroupMethod<T> SelectWhere(Func<System.Reflection.MethodInfo, bool> predicate)
        {
            predicate.NotNull("predicate");
            var methods = typeof(T)
                .GetMethodsToIntercept()
                .Where(m => predicate(m));
            RegisterSignatures(methods.Select(m => m.ExtractMethodSignature()));
            return this;
        }

        public GroupMethod<T> SelectPropertyGetter(Expression<Func<T, object>> getter)
        {
            getter.NotNull("expression");
            var exp = getter.GetMemberOfExpression().Where(c => c.Name.StartsWith("get_")).First();

            if (!typeof(T).IsInterface)
                RequireHelper.Overridable(exp);

            var signature = new MethodSign(exp);

            RegisterSignatures(new[] { signature });

            return this;
        }

        public GroupMethod<T> SelectPropertySetter(Expression<Func<T, object>> setter)
        {

            setter.NotNull("expression");
            var exp = setter.GetMemberOfExpression().Where(c => c.Name.StartsWith("set_")).First();

            if (!typeof(T).IsInterface)
                RequireHelper.Overridable(exp);

            var signature = new MethodSign(exp);

            RegisterSignatures(new[] { signature });

            return this;

        }

        #endregion


        //public GroupMethod<T> AddInterceptor<U>(Expression<Func<U>> e = null)
        //{           
        //    Type t = typeof(U);
        //    if (!Interceptors.ContainsKey(t))            
        //        Interceptors.Add(t, new InterceptorTypeBox(t, e));
        //    return this;
        //}


        public GroupMethod<T> AddInterceptor(InterceptEnumEventType typeEvent, Action<object, InterceptEventArgs, int> e)
        {

            Type t = e.Method.DeclaringType;

            if (!Interceptors.ContainsKey(t))
                Interceptors.Add(t, new InterceptorDelegateBox(typeEvent, e));
            else
            {
                InterceptorDelegateBox j = Interceptors[t] as InterceptorDelegateBox;
                j.SetMethods(typeEvent, e);
            }

            return this;

        }


    }

}






/*
         //public Proxy<T> OnBefore(Action action)
        //{
        //    Require.ArgumentNotNull("action", action);
        //    var callback = new OnBeforeCallback(action);
        //    interceptedMembers.ForEach(ms => register[ms].Add(callback));
        //    return this;
        //}


        //public Proxy<T> OnBefore(Action<IMethodInvocation> action)
        //{
        //    Require.ArgumentNotNull("action", action);
        //    var callback = new OnBeforeCallback(action);
        //    interceptedMembers.ForEach(e => register[e].Add(callback));
        //    return this;
        //}


        //public Proxy<T> OnInvoke(Func<IMethodInvocation, object> action)
        //{
        //    Require.ArgumentNotNull("action", action);
        //    var callback = new OnInvokeCallback(action);
        //    interceptedMembers.ForEach(e => register[e].Add(callback));
        //    return this;
        //}


        //public Proxy<T> OnInvoke(Action<IMethodInvocation> action)
        //{
        //    Require.ArgumentNotNull("action", action);
        //    var callback = new OnInvokeCallback(action);
        //    interceptedMembers.ForEach(e => register[e].Add(callback));
        //    return this;
        //}


        //public Proxy<T> OnCatch(Action<Exception> action)
        //{
        //    Require.ArgumentNotNull("action", action);
        //    var callback = new OnCatchCallback(action);
        //    interceptedMembers.ForEach(e => register[e].Add(callback));
        //    return this;
        //}


        //public Proxy<T> OnCatch(Action<IMethodInvocation, Exception> action)
        //{
        //    Require.ArgumentNotNull("action", action);
        //    var callback = new OnCatchCallback(action);
        //    interceptedMembers.ForEach(e => register[e].Add(callback));
        //    return this;
        //}


        //public Proxy<T> OnAfter(Action action)
        //{
        //    Require.ArgumentNotNull("action", action);
        //    var callback = new OnAfterCallback(action);
        //    interceptedMembers.ForEach(e => register[e].Add(callback));
        //    return this;
        //}


        //public Proxy<T> OnAfter(Action<IMethodInvocation> action)
        //{
        //    Require.ArgumentNotNull("action", action);
        //    var callback = new OnAfterCallback(action);
        //    interceptedMembers.ForEach(e => register[e].Add(callback));
        //    return this;
        //}

  
        //public Proxy<T> OnReturn(Func<object> action)
        //{
        //    Require.ArgumentNotNull("action", action);
        //    var callback = new OnReturnCallback(action);
        //    interceptedMembers.ForEach(e => register[e].Add(callback));
        //    return this;
        //}


        //public Proxy<T> OnReturn(Func<IMethodInvocation, object, object> action)
        //{
        //    Require.ArgumentNotNull("action", action);
        //    var callback = new OnReturnCallback(action);
        //    interceptedMembers.ForEach(e => register[e].Add(callback));
        //    return this;
        //}  
 */
